package pl.edu.mimuw.irs.core.model.design;

import java.util.LinkedHashSet;
import java.util.Set;

import pl.edu.mimuw.irs.core.exception.InternalException;
import pl.edu.mimuw.irs.core.exception.InternalException.Cause;
import pl.edu.mimuw.irs.core.model.analysis.AnalysisWorkflow;
import pl.edu.mimuw.irs.core.model.design.Fragmentation.Type;
import pl.edu.mimuw.irs.core.model.petrinet.INode;
import pl.edu.mimuw.irs.core.model.petrinet.Place;
import pl.edu.mimuw.irs.core.model.petrinet.workflow.Workflow;
import pl.edu.mimuw.irs.core.util.Converter;
import pl.edu.mimuw.irs.core.util.Position;


/**
 * @author Jakub Rauch
 * Created on: 2009-05-16
 */
public class IRSWorkflow extends Workflow {

	// *** Attributes
	
	private IRSPlace rootPlace;
	private Set<IRSResourceSet> resources;
	private Set<IRSActivity> activities;
	public IRSPlace getRootPlace() {
		return rootPlace;
	}
	public void setRootPlace(IRSPlace rootPlace) {
		this.rootPlace = rootPlace;
		rootPlace.setNet(this);
	}
	public Set<IRSResourceSet> getResources() {
		return resources;
	}
	public void setResources(Set<IRSResourceSet> resources) {
		this.resources = resources;
	}
	public Set<IRSActivity> getActivities() {
		return activities;
	}
	public void setActivities(Set<IRSActivity> activities) {
		this.activities = activities;
	}
	
	// *** Methods

	public void createSampleModel() {
		setRootPlace(new IRSPlace(new Position(50, 50)));
		getRootPlace().setFragmentation(new Fragmentation(Type.SEQUENCE));
		getRootPlace().getChildren().get(1).setFragmentation(new Fragmentation(Type.ACTIVITY));
	}
	
	public void verifyWorkflow() {
		// TODO verify workflow
	}
	
	public AnalysisWorkflow getAnalysisWorkflow() {
		return new AnalysisWorkflow(this);
	}
	
	@Override
	public Set<INode> getAllNodes() {
		Set<INode> nodes = new LinkedHashSet<INode>();
		for (INode node : getRootPlace().getExpandedNodes()) {
			nodes.add(node);
		}
		return nodes; // FIXME powinno zwracać to inaczej - kopiować i wyrzucać zbędne łuki!
	}
	/*
	@Override
	public Collection<Place> getPlaces() {
		Set<Place> nodes = new LinkedHashSet<Place>();
		for (INode node : getRootPlace().getExpandedNodes()) {
			if (node instanceof Place) {
				nodes.add((Place)node);
			}
		}
		return nodes;
	}

	@Override
	public Collection<Transition> getTransitions() {
		Set<Transition> nodes = new LinkedHashSet<Transition>();
		for (INode node : getRootPlace().getExpandedNodes()) {
			if (node instanceof Place) {
				nodes.add((Transition)node);
			}
		}
		return nodes;
	}
	*/
	
	protected void locateInOut() {
		boolean foundIn = false;
		boolean foundOut = false;
		setIn(null);
		setOut(null);
		
		for (Place place : getPlaces()) {
			if (place instanceof IRSPlace) {
				IRSPlace irsPlace = Converter.asIRSPlace(place);
				if (irsPlace.getIncomingArcs().size() == 0 &&
						irsPlace.isAtomic()) {
					if (foundIn) throw new InternalException(Cause.WORKFLOW_TOO_MANY_IN_PLACES);
					setIn(place);
					foundIn = true;
				}
			}
		}

		for (Place place : getPlaces()) {
			if (place instanceof IRSPlace) {
				IRSPlace irsPlace = Converter.asIRSPlace(place);
				if (irsPlace.getOutgoingArcs().size() == 0 &&
						irsPlace.isAtomic()) {
					if (foundOut) throw new InternalException(Cause.WORKFLOW_TOO_MANY_OUT_PLACES);
					setOut(place);
					foundOut = true;
				}
			}
		}
		
		if (!foundIn) throw new InternalException(Cause.WORKFLOW_NO_IN_PLACE);
		if (!foundOut) throw new InternalException(Cause.WORKFLOW_OUT_PLACE);
	}
}
